#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <jpeglib.h>

/**
 * 生成JPEG图像的灰度直方图
 * @param filename JPEG文件路径
 * @param scale_factor 缩放因子，用于控制输出柱状图的大小
 * @param output_file 输出文件，如果为NULL则输出到控制台
 */
void generate_histogram(const char *filename, int scale_factor, const char *output_file) {
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    FILE *infile = fopen(filename, "rb");
    if (!infile) {
        fprintf(stderr, "错误: 无法打开文件 '%s'\n", filename);
        return;
    }

    // 设置错误处理
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, infile);
    
    // 读取JPEG头信息
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) {
        fprintf(stderr, "错误: 无效的JPEG文件格式\n");
        fclose(infile);
        return;
    }
    
    // 强制输出为RGB格式
    cinfo.out_color_space = JCS_RGB;
    jpeg_start_decompress(&cinfo);

    int width = cinfo.output_width;
    int height = cinfo.output_height;
    int components = cinfo.output_components;
    int histogram[256] = {0}; // 存储每个灰度值的计数
    
    printf("正在处理JPEG图像: %dx%d 像素, %d通道\n", width, height, components);
    
    // 分配行缓冲区
    unsigned char *buffer = (unsigned char *)malloc(width * components);
    if (!buffer) {
        fprintf(stderr, "错误: 内存分配失败\n");
        jpeg_finish_decompress(&cinfo);
        jpeg_destroy_decompress(&cinfo);
        fclose(infile);
        return;
    }
    
    // 读取像素数据并计算灰度直方图
    while (cinfo.output_scanline < height) {
        jpeg_read_scanlines(&cinfo, &buffer, 1);
        
        for (int x = 0; x < width; x++) {
            unsigned char gray;
            
            if (components == 3) {
                // RGB图像，使用标准加权平均
                unsigned char r = buffer[x * 3];
                unsigned char g = buffer[x * 3 + 1];
                unsigned char b = buffer[x * 3 + 2];
                gray = (unsigned char)(0.299 * r + 0.587 * g + 0.114 * b);
            } else if (components == 1) {
                // 灰度图像
                gray = buffer[x];
            } else {
                // 其他格式，使用简单平均
                int sum = 0;
                for (int c = 0; c < components; c++) {
                    sum += buffer[x * components + c];
                }
                gray = (unsigned char)(sum / components);
            }
            
            histogram[gray]++;
        }
    }

    // 清理资源
    free(buffer);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    
    // 找到最大值用于缩放
    int max_count = 0;
    int total_pixels = width * height;
    for (int i = 0; i < 256; i++) {
        if (histogram[i] > max_count) {
            max_count = histogram[i];
        }
    }
    
    FILE *output = stdout;
    if (output_file) {
        output = fopen(output_file, "w");
        if (!output) {
            fprintf(stderr, "警告: 无法创建输出文件，使用控制台输出\n");
            output = stdout;
        }
    }
    
    fprintf(output, "\n=== JPEG灰度直方图分析 ===\n");
    fprintf(output, "图像尺寸: %dx%d\n", width, height);
    fprintf(output, "颜色通道: %d\n", components);
    fprintf(output, "总像素数: %d\n", total_pixels);
    fprintf(output, "最大频次: %d\n\n", max_count);
    
    // 打印柱状图
    for (int i = 0; i < 256; i++) {
        if (histogram[i] > 0) { // 只显示有数据的灰度值
            double percentage = (double)histogram[i] / total_pixels * 100;
            int bar_length = (histogram[i] * scale_factor) / (max_count > 0 ? max_count : 1);
            
            fprintf(output, "%3d (%6.2f%%): ", i, percentage);
            for (int j = 0; j < bar_length; j++) {
                fprintf(output, "█");
            }
            fprintf(output, " (%d)\n", histogram[i]);
        }
    }
    
    if (output_file && output != stdout) {
        fclose(output);
        printf("直方图已保存到: %s\n", output_file);
    }
}

/**
 * 显示使用帮助信息
 */
void print_usage(const char *program_name) {
    printf("用法: %s <JPEG文件> [选项]\n", program_name);
    printf("选项:\n");
    printf("  -s <数值>    设置柱状图缩放因子 (默认: 50)\n");
    printf("  -o <文件>    输出到指定文件\n");
    printf("  -h          显示此帮助信息\n");
    printf("\n示例:\n");
    printf("  %s image.jpg\n", program_name);
    printf("  %s image.jpg -s 30 -o histogram.txt\n", program_name);
    printf("\n支持的格式:\n");
    printf("  - JPEG/JPG图像文件\n");
    printf("  - RGB和灰度图像\n");
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        print_usage(argv[0]);
        return 1;
    }
    
    const char *filename = argv[1];
    int scale_factor = 50;
    const char *output_file = NULL;
    
    // 解析命令行参数
    for (int i = 2; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0) {
            print_usage(argv[0]);
            return 0;
        } else if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) {
            scale_factor = atoi(argv[++i]);
            if (scale_factor <= 0) {
                fprintf(stderr, "错误: 缩放因子必须为正数\n");
                return 1;
            }
        } else if (strcmp(argv[i], "-o") == 0 && i + 1 < argc) {
            output_file = argv[++i];
        } else {
            fprintf(stderr, "错误: 未知参数 '%s'\n", argv[i]);
            print_usage(argv[0]);
            return 1;
        }
    }
    
    // 检查文件是否存在
    FILE *test_file = fopen(filename, "rb");
    if (!test_file) {
        fprintf(stderr, "错误: 文件 '%s' 不存在或无法访问\n", filename);
        return 1;
    }
    fclose(test_file);
    
    printf("开始分析JPEG文件: %s\n", filename);
    generate_histogram(filename, scale_factor, output_file);
    
    return 0;
}

/*
 * 编译说明:
 * gcc jpg_histogram.c -o jpg_histogram -ljpeg
 * 
 * 依赖库:
 * - libjpeg-dev (Ubuntu/Debian)
 * - libjpeg-devel (CentOS/RHEL)
 * - jpeg (macOS via Homebrew)
 */